import time
import random
import logging
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from appium.options.android import UiAutomator2Options

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class WeChatAutomation:
    def __init__(self):
        # Appium服务器配置
        # 在__init__方法中修改desired_caps定义
        self.desired_caps = {
            "platformName": "Android",
            "appium:platformVersion": "12",
            "appium:deviceName": "SM-G988N",
            "appium:automationName": "UiAutomator2",
            "appium:udid": "",  # 自动获取设备ID
            "appium:adbExecTimeout": 45000,
            "appium:androidInstallTimeout": 180000,
            "appium:appPackage": "com.tencent.mm",
            "appium:appActivity": ".ui.LauncherUI",
            "appium:noReset": True
        }

        # 在connect方法中创建Options对象
        options = UiAutomator2Options().load_capabilities(self.desired_caps)
        self.driver = webdriver.Remote('http://localhost:4723/wd/hub', options=options)  # 更新端口号
        self.wait = None
        
    def _verify_environment(self):
        """环境预检"""
        try:
            subprocess.check_output(['adb', 'version'], timeout=5)
            logger.info("ADB环境验证成功")
            return True
        except Exception as e:
            logger.error(f"ADB环境异常: {str(e)}")
            return False

    def connect(self):
        """连接到Appium服务器和安卓设备"""
        try:
            options = UiAutomator2Options().load_capabilities(self.desired_caps)
            if not self._verify_environment():
                raise RuntimeError("Android环境配置异常，请检查SDK路径和adb可用性")
            self.driver = webdriver.Remote('http://localhost:4723/wd/hub', options=options)
            self.wait = WebDriverWait(self.driver, 30)
            logger.info("成功连接到Appium服务器和安卓设备")
            time.sleep(8)  # 等待微信完全启动
            return True
        except Exception as e:
            logger.error(f"连接失败: {str(e)}")
            return False
    
    def disconnect(self):
        """断开与Appium服务器的连接"""
        if self.driver:
            self.driver.quit()
            logger.info("已断开与Appium服务器的连接")
    
    def add_friends(self, contact_list):
        """批量添加好友"""
        logger.info(f"开始批量添加好友，共{len(contact_list)}个")
        
        for contact in contact_list:
            try:
                # 点击"通讯录"
                # 混合定位策略：先尝试ID定位，失败后使用文本定位
                self._smart_click(
                    preferred_locator=(AppiumBy.ID, 'com.tencent.mm:id/f2y'),
                    fallback_locator=(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("通讯录")')
                )
                
                # 点击"添加朋友"
                self._click_element((AppiumBy.XPATH, '//*[@text="添加朋友"]'))
                
                # 输入搜索内容
                search_box = self.wait.until(
                    EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                )
                search_box.send_keys(contact)
                time.sleep(2)
                
                # 点击搜索结果
                self._click_element((AppiumBy.XPATH, '//*[@text="搜索结果"]/following-sibling::android.widget.LinearLayout'))
                
                # 点击"添加到通讯录"
                self._click_element((AppiumBy.XPATH, '//*[@text="添加到通讯录"]'))
                
                # 输入验证消息
                verify_msg = self.wait.until(
                    EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/dtv'))
                )
                verify_msg.send_keys("你好，我是通过商机平台添加你的")
                
                # 点击"发送"
                self._click_element((AppiumBy.XPATH, '//*[@text="发送"]'))
                
                logger.info(f"成功发送添加请求给: {contact}")
                # 随机等待 8- 10秒，避免操作过快
                time.sleep(random.randint(8,10))
                
            except Exception as e:
                logger.error(f"添加好友 {contact} 失败: {str(e)}")
                # 出现错误时，返回首页
                self._back_to_home()
                time.sleep(3)
    
    def recommend_business_opportunity(self, user_list, business_link):
        """自动推荐商机"""
        logger.info(f"开始推荐商机，共{len(user_list)}个用户")
        
        for user in user_list:
            try:
                # 点击"通讯录"
                self._click_element((AppiumBy.XPATH, '//*[@text="通讯录"]'))
                
                # 点击搜索图标
                self._click_element((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                
                # 输入用户名
                search_box = self.wait.until(
                    EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                )
                search_box.send_keys(user)
                time.sleep(2)
                
                # 点击搜索结果
                self._click_element((AppiumBy.XPATH, f'//*[@text="{user}"]'))
                
                # 点击"发消息"
                self._click_element((AppiumBy.XPATH, '//*[@text="发消息"]'))
                
                # 点击输入框
                input_box = self.wait.until(
                    EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/dtv'))
                )
                input_box.click()
                
                # 输入商机链接
                input_box.send_keys(f"你好，给你推荐一个商机：{business_link}")
                
                # 点击"发送"
                self._click_element((AppiumBy.XPATH, '//*[@text="发送"]'))
                
                logger.info(f"成功向 {user} 推荐商机")
                # 随机等待2-5秒
                time.sleep(random.randint(2, 5))
                
            except Exception as e:
                logger.error(f"向 {user} 推荐商机失败: {str(e)}")
                # 出现错误时，返回首页
                self._back_to_home()
                time.sleep(3)
    
    def mass_send(self, content_type, content, receiver_list):
        """自动群发收藏、文字、图片、链接等"""
        logger.info(f"开始群发{content_type}，共{len(receiver_list)}个接收者")
        
        for receiver in receiver_list:
            try:
                # 点击"通讯录"
                self._click_element((AppiumBy.XPATH, '//*[@text="通讯录"]'))
                
                # 点击搜索图标
                self._click_element((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                
                # 输入接收者名称
                search_box = self.wait.until(
                    EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                )
                search_box.send_keys(receiver)
                time.sleep(2)
                
                # 点击搜索结果
                self._click_element((AppiumBy.XPATH, f'//*[@text="{receiver}"]'))
                
                # 点击"发消息"
                self._click_element((AppiumBy.XPATH, '//*[@text="发消息"]'))
                
                # 根据内容类型选择发送方式
                if content_type == "text":
                    # 发送文字
                    input_box = self.wait.until(
                        EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/dtv'))
                    )
                    input_box.send_keys(content)
                    self._click_element((AppiumBy.XPATH, '//*[@text="发送"]'))
                
                elif content_type == "link":
                    # 发送链接
                    input_box = self.wait.until(
                        EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/dtv'))
                    )
                    input_box.send_keys(content)
                    self._click_element((AppiumBy.XPATH, '//*[@text="发送"]'))
                
                elif content_type == "image":
                    # 发送图片
                    self._click_element((AppiumBy.ID, 'com.tencent.mm:id/axm'))  # 点击"+"按钮
                    self._click_element((AppiumBy.XPATH, '//*[@text="图片"]'))  # 点击"图片"
                    # 选择图片（需要根据实际图片位置调整）
                    self._click_element((AppiumBy.XPATH, '//android.widget.GridView/android.widget.ImageView[1]'))
                    self._click_element((AppiumBy.XPATH, '//*[@text="发送"]'))
                
                elif content_type == "favorite":
                    # 发送收藏
                    self._click_element((AppiumBy.ID, 'com.tencent.mm:id/axm'))  # 点击"+"按钮
                    self._click_element((AppiumBy.XPATH, '//*[@text="收藏"]'))  # 点击"收藏"
                    # 选择收藏项（需要根据实际收藏内容调整）
                    self._click_element((AppiumBy.XPATH, '//android.widget.ListView/android.widget.LinearLayout[1]'))
                    self._click_element((AppiumBy.XPATH, '//*[@text="发送"]'))
                
                logger.info(f"成功向 {receiver} 发送{content_type}")
                # 随机等待2-5秒
                time.sleep(random.randint(2, 5))
                
            except Exception as e:
                logger.error(f"向 {receiver} 发送{content_type}失败: {str(e)}")
                # 出现错误时，返回首页
                self._back_to_home()
                time.sleep(3)
    
    def create_group_chat(self, group_name, member_list):
        """创建微信群"""
        logger.info(f"开始创建微信群: {group_name}，成员:{member_list}")
        
        try:
            # 点击"通讯录"
            self._click_element((AppiumBy.XPATH, '//*[@text="通讯录"]'))
            
            # 点击右上角"+"
            self._click_element((AppiumBy.ID, 'com.tencent.mm:id/j6'))
            
            # 点击"发起群聊"
            self._click_element((AppiumBy.XPATH, '//*[@text="发起群聊"]'))
            
            # 选择群成员
            for member in member_list:
                # 点击搜索图标
                self._click_element((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                
                # 输入成员名称
                search_box = self.wait.until(
                    EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
                )
                search_box.send_keys(member)
                time.sleep(2)
                
                # 选择成员
                self._click_element((AppiumBy.XPATH, f'//*[@text="{member}"]/preceding-sibling::android.widget.CheckBox'))
                
                # 返回
                self._click_element((AppiumBy.ID, 'com.tencent.mm:id/i6'))
            
            # 点击"完成"
            self._click_element((AppiumBy.XPATH, '//*[@text="完成"]'))
            
            # 设置群名称
            self._click_element((AppiumBy.ID, 'com.tencent.mm:id/i6'))  # 点击群聊名称
            group_name_input = self.wait.until(
                EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/dtv'))
            )
            group_name_input.send_keys(group_name)
            self._click_element((AppiumBy.XPATH, '//*[@text="保存"]'))
            
            logger.info(f"成功创建微信群: {group_name}")
            
        except Exception as e:
            logger.error(f"创建微信群失败: {str(e)}")
            # 出现错误时，返回首页
            self._back_to_home()
            time.sleep(3)
    
    def add_remark_and_tag(self, contact_name, remark, tags=None):
        """自动备注标签"""
        logger.info(f"开始为 {contact_name} 添加备注和标签")
        
        try:
            # 点击"通讯录"
            self._click_element((AppiumBy.XPATH, '//*[@text="通讯录"]'))
            
            # 点击搜索图标
            self._click_element((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
            
            # 输入联系人名称
            search_box = self.wait.until(
                EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/bhn'))
            )
            search_box.send_keys(contact_name)
            time.sleep(2)
            
            # 点击搜索结果
            self._click_element((AppiumBy.XPATH, f'//*[@text="{contact_name}"]'))
            
            # 点击右上角"..."
            self._click_element((AppiumBy.ID, 'com.tencent.mm:id/j6'))
            
            # 点击"设置备注和标签"
            self._click_element((AppiumBy.XPATH, '//*[@text="设置备注和标签"]'))
            
            # 输入备注名
            remark_input = self.wait.until(
                EC.presence_of_element_located((AppiumBy.XPATH, '//*[@text="备注名"]/following-sibling::android.widget.EditText'))
            )
            remark_input.clear()
            remark_input.send_keys(remark)
            
            # 添加标签（如果有）
            if tags:
                self._click_element((AppiumBy.XPATH, '//*[@text="标签"]'))
                for tag in tags:
                    # 点击"添加标签"
                    self._click_element((AppiumBy.XPATH, '//*[@text="添加标签"]'))
                    
                    # 输入标签名
                    tag_input = self.wait.until(
                        EC.presence_of_element_located((AppiumBy.ID, 'com.tencent.mm:id/dtv'))
                    )
                    tag_input.send_keys(tag)
                    
                    # 点击"确定"
                    self._click_element((AppiumBy.XPATH, '//*[@text="确定"]'))
                
                # 返回
                self._click_element((AppiumBy.ID, 'com.tencent.mm:id/i6'))
            
            # 点击"完成"
            self._click_element((AppiumBy.XPATH, '//*[@text="完成"]'))
            
            logger.info(f"成功为 {contact_name} 添加备注: {remark} 和标签: {tags}")
            
        except Exception as e:
            logger.error(f"为 {contact_name} 添加备注和标签失败: {str(e)}")
            # 出现错误时，返回首页
            self._back_to_home()
            time.sleep(3)
    
    def _smart_click(self, preferred_locator, fallback_locator=None):
        """智能点击机制（带备用定位策略）"""
        try:
            # 首选定位方式
            return self._click_element(preferred_locator)
        except Exception as e:
            if fallback_locator:
                logger.warning(f"首选定位方式失败，尝试备用方案｜{str(e)}")
                # 执行备用定位策略
                return self._click_element(fallback_locator)
            raise

    def _click_element(self, locator):
        """增强版元素点击机制（带随机等待和页面诊断）"""
        max_retries = 5
        base_wait = 1.5
        diagnostic_info = ''

        for attempt in range(max_retries):
            try:
                # 先等待元素存在
                self.wait.until(EC.presence_of_element_located(locator))
                # 再等待可点击
                element = self.wait.until(EC.element_to_be_clickable(locator))
                
                # 模拟人类操作：随机等待+滚动到视图
                self.driver.execute_script("arguments[0].scrollIntoViewIfNeeded();", element)
                time.sleep(base_wait + random.random()*1.5)
                
                element.click()
                return True
                
            except Exception as e:
                diagnostic_info = f"定位器: {locator}\n当前页面: {self.driver.page_source[:500]}..."
                logger.error(f"点击失败第{attempt+1}次: {str(e)}\n诊断信息: {diagnostic_info}")
                
                # 失败时截图
                timestamp = time.strftime("%Y%m%d_%H%M%S")
                self.driver.save_screenshot(f"click_error_{timestamp}.png")
                
                # 随机回退策略
                time.sleep(base_wait * (attempt+1) + random.random()*3)
                
                if attempt == max_retries - 1:
                    raise RuntimeError(f"元素点击失败已达最大重试次数｜{diagnostic_info}") from e
    
    def _back_to_home(self):
        """返回微信首页"""
        try:
            # 多次点击返回键，直到回到首页
            for _ in range(5):
                self.driver.back()
                time.sleep(1)
                
                # 检查是否回到首页
                try:
                    self.wait.until(EC.presence_of_element_located((AppiumBy.XPATH, '//*[@text="微信"]')))
                    break
                except:
                    continue
        except Exception as e:
            logger.error(f"返回首页失败: {str(e)}")
            # 如果返回失败，尝试重新连接
            self.disconnect()
            self.connect()

# 使用示例
if __name__ == "__main__":
    wechat = WeChatAutomation()
    
    # 连接到设备
    if wechat.connect():
        try:
            # 1. 自动批量添加好友
            wechat.add_friends(["Robin_jj", "联系人2", "联系人3"])
            
            # 2. 自动推荐商机
            # business_link = "https://mp.weixin.qq.com/s/xxxxxx"  # 商机多公众号链接
            # wechat.recommend_business_opportunity(["好友1", "好友2", "好友3"], business_link)
            
            # 3. 自动群发（文字）
            # wechat.mass_send("text", "这是一条测试消息", ["好友1", "好友2", "好友3"])
            
            # 4. 自动群发（链接）
            # wechat.mass_send("link", "https://mp.weixin.qq.com/s/xxxxxx", ["好友1", "好友2", "好友3"])
            
            # 5. 创建微信群
            # wechat.create_group_chat("测试群", ["好友1", "好友2", "好友3"])
            
            # 6. 自动备注标签
            # wechat.add_remark_and_tag("好友1", "备注名", ["标签1", "标签2"])
            
            logger.info("所有任务执行完毕")
        except Exception as e:
            logger.error(f"执行任务时发生错误: {str(e)}")
        finally:
            # 断开连接
            wechat.disconnect()
    else:
        logger.error("连接失败，无法执行任务")